package com.wzcl.app.service.impl;

import com.alibaba.fastjson.JSON;
import com.wzcl.app.dao.model.*;
import com.wzcl.app.dao.repository.CourseRepository;
import com.wzcl.app.dao.repository.SubjectRepository;
import com.wzcl.app.dao.repository.UserCourseRepository;
import com.wzcl.app.model.common.*;
import com.wzcl.app.model.dto.UserCourseDto;
import com.wzcl.app.model.dto.UserCoursePageDto;
import com.wzcl.app.service.CourseService;
import com.wzcl.app.service.UserCourseService;
import com.wzcl.app.utils.BeanUtil;
import com.wzcl.app.utils.CollectionUtil;
import com.wzcl.app.model.common.PageUtil;
import com.wzcl.app.utils.WordChangeUtil;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import javax.persistence.criteria.*;
import java.util.*;
import java.util.stream.Collectors;

@Log4j2
@Service
@Transactional
public class UserCourseServiceImpl implements UserCourseService {

    @Resource
    private UserCourseRepository repository;
    @Resource
    private CourseService courseService;
    @Resource
    private SubjectRepository subjectRepository;
    @Resource
    private UserCourseRepository userCourseRepository;

    @Override
    public UserCourse getUserCourseById(Integer id) {
        return repository.findById(id).orElse(null);
    }

    @Override
    public UserCourse findByPhoneAndCourseIdAndSpec(String userPhone, Integer courseId,String spec) {
        if(StringUtils.isBlank(spec)){
            return repository.findByPhoneAndCourseIdAndSpecNull(userPhone,courseId);
        }else {
            return repository.findByPhoneAndCourseIdAndSpec(userPhone,courseId,spec);
        }

    }

    @Override
    public UserCourse checkUserCourse(String userPhone, Integer id) {
        UserCourse userCourse = repository.findByPhoneAndCourseIdAndSpecNull(userPhone, id);
        if(userCourse == null){
            throw new BusinessException(CodeMsg.USER_COURSE_NOT_EXIST);
        }
        return userCourse;
    }

    @Override
    public List<UserCourse> getUserCourseList(UserCourseDto userCourseDto) {
        return repository.findAll(getSpecification(userCourseDto),userCourseDto.getSort());
    }

    @Override
    public MyPage<UserCourse> getUserCoursePage(UserCourseDto userCourseDto) {
        Page<UserCourse> all = repository.findAll(getSpecification(userCourseDto), userCourseDto.getPageable());
        ArrayList<UserCourse> list = new ArrayList<>(all.getContent());
        Collections.reverse(list);
        MyPage<UserCourse> myPage = new MyPage<>();
        myPage.setContent(list);
        myPage.setTotalElements(all.getTotalElements());
        return myPage;
    }


    @Override
    public void addUserCourseByMap(AppUser user, Map<Integer, Course> courseMap, Map<Integer, Set<String>> specMap) {
        //获取已有的课程
        UserCourseDto userCourseDto = new UserCourseDto();
        userCourseDto.setUserPhone(user.getPhone());
        List<UserCourse> userCourses = getUserCourseList(userCourseDto);
        //用于新增
        List<UserCourse> userCourseList = new ArrayList<>();
        //除去重复的
        Set<Integer> key = specMap.keySet();
        for (Integer courseId : key) {
            Course course = courseMap.get(courseId);
            for (String spec : specMap.get(courseId)){
                boolean exist = false;
                for (UserCourse userCourse : userCourses) {
                    if(userCourse.getCourse().getId().equals(courseId) && StringUtils.equals(userCourse.getSpec(),spec)){
                        exist = true;
                        break;
                    }
                }
                if(!exist){
                    UserCourse userCourse = new UserCourse();
                    userCourse.setUserId(user.getId());
                    userCourse.setUserPhone(user.getPhone());
                    course.setRealSaleVolume(course.getRealSaleVolume()+1);
                    userCourse.setCourse(course);
                    userCourse.setSpec(spec);
                    userCourseList.add(userCourse);
                }
            }
        }
        if(userCourseList.size()>0){
            userCourseList = repository.saveAll(userCourseList);
            log.info("User completes course:{} purchase", JSON.toJSONString(userCourseList));
        }
    }

    @Override
    public void delUserCourseByMap(AppUser user, Map<Integer, Course> courseMap, Map<Integer, Set<String>> specMap) {
        //获取已有的课程
        UserCourseDto userCourseDto = new UserCourseDto();
        userCourseDto.setUserPhone(user.getPhone());
        List<UserCourse> userCourses = getUserCourseList(userCourseDto);
        //用于删除
        List<UserCourse> userCourseList = new ArrayList<>();
        //找到符合的重复的
        Set<Integer> key = specMap.keySet();
        for (Integer courseId : key) {
            for (String spec : specMap.get(courseId)){
                for (UserCourse userCourse : userCourses) {
                    if(userCourse.getCourse().getId().equals(courseId) && StringUtils.equals(userCourse.getSpec(),spec)){
                        userCourseList.add(userCourse);
                        break;
                    }
                }
            }
        }
        if(userCourseList.size()>0){
            repository.deleteAll(userCourseList);
            log.info("User completes course:{} purchase", JSON.toJSONString(userCourseList));
        }
    }

    public void delUserCourseByCourseList(AppUser user, List<Course> courseList) {
        //获取已有的课程
        UserCourseDto userCourseDto = new UserCourseDto();
        userCourseDto.setUserPhone(user.getPhone());
        List<UserCourse> userCourses = getUserCourseList(userCourseDto);
        //除去没有重复的
        if(userCourses!=null && userCourses.size()>0){
            List<UserCourse> collect = userCourses.stream().filter(userCourse -> {
                for (Course course : courseList) {
                    if(course.getId().equals(userCourse.getCourse().getId())) {
                        course.setRealSaleVolume(course.getRealSaleVolume()-1);
                        courseService.saveCourse(course);
                        return true;
                    }
                }
                return false;
            }).collect(Collectors.toList());
            if(collect.size()>0){
                repository.deleteAll(collect);
                log.info("User completes course:{} remove", JSON.toJSONString(collect));
            }
        }
    }

    @Override
    public List<UserCourse> findByPhoneAndCourseId(String phone, Integer courseId) {
        List<UserCourse> list = repository.findByPhoneAndCourseId(phone, courseId);
        if(list == null){
            return  Collections.emptyList();
        }
        return list;
    }

    @Override
    public String getUserCourse(UserCoursePageDto userCoursePageDto) {
        String phone = SecurityContextHolder.getContext().getAuthentication().getName();
        List<UserCourse> all = repository.findAllByUserPhone(phone);
        List<UserCourseDto> userCourseDtoList = new ArrayList<>();
        for (int index = 0; index <all.size(); index++) {
            UserCourseDto userCourseDto = BeanUtil.convertBean(all.get(index), UserCourseDto.class);
            //获取中文难度
            // TODO 脏数据导致NullPointerException
            userCourseDto.setHardZh(WordChangeUtil.getHard(all.get(index).getCourse().getHard()));
            userCourseDto.setSubjectId(all.get(index).getCourse().getSubject().getId());
            userCourseDto.setCourseType(all.get(index).getCourse().getCourseType());
            //获取学科
            userCourseDto.setSubjectZh(subjectRepository.findNameById(all.get(index).getCourse().getSubject().getId()));
            userCourseDtoList.add(userCourseDto);
        }
        //根据科目id和课程类型id做筛选
        if (userCoursePageDto.getCourseTypeId() != null && userCoursePageDto.getSubjectId() != null){
            for (int index = 0; index < userCourseDtoList.size(); index++) {
                if (userCourseDtoList.get(index).getCourseType() != userCoursePageDto.getCourseTypeId() || userCourseDtoList.get(index).getSubjectId() != userCoursePageDto.getSubjectId()){
                    userCourseDtoList.remove(index);
                    index--;
                }
            }
        }else if (userCoursePageDto.getCourseTypeId() != null && userCoursePageDto.getSubjectId() == null){
            for (int index = 0; index < userCourseDtoList.size(); index++) {
                if (userCourseDtoList.get(index).getCourseType() != userCoursePageDto.getCourseTypeId()){
                    userCourseDtoList.remove(index);
                    index--;
                }
            }
        }else if (userCoursePageDto.getSubjectId() != null && userCoursePageDto.getCourseTypeId() == null){

            for (int index = 0; index < userCourseDtoList.size(); index++) {
                if (userCourseDtoList.get(index).getSubjectId() != userCoursePageDto.getSubjectId()){
                    userCourseDtoList.remove(index);
                    index--;
                }
            }
        }
        List<UserCourseDto> listByPage = CollectionUtil.getListByPage(userCourseDtoList, userCoursePageDto.getCurrentPage(), userCoursePageDto.getPageSize());
        PageUtil<UserCourseDto> userCoursePage = new PageUtil<>(userCoursePageDto.getCurrentPage(), userCoursePageDto.getPageSize(), all.size());
        userCoursePage.setCurrentPage(userCoursePage.getCurrentPage());
        userCoursePage.setPageSize(userCoursePage.getPageSize());
        userCoursePage.setContent(listByPage);
        String json = JSON.toJSONString(userCoursePage);
        return json;
    }

    @Override
    public List<Course> retrieveUserCourseByUserId(Integer userId) {
        List<Course> courseList = userCourseRepository.findUserCourseByUserId(userId);
        return courseList;
    }

    private Specification<UserCourse> getSpecification(UserCourseDto userCourseDto){
        return new Specification<UserCourse>() {
            @Override
            public Predicate toPredicate(Root<UserCourse> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<Predicate>();
                if(!StringUtils.isBlank(userCourseDto.getUserPhone())){
                    predicates.add(criteriaBuilder.equal(root.get("userPhone"),userCourseDto.getUserPhone()));
                }
                if(userCourseDto.getCourseType() != null || userCourseDto.getSubjectId() != null){
                    Join<UserCourse, Course> coursePath = root.join("course");
                    if(userCourseDto.getCourseType() != null){
                        predicates.add(criteriaBuilder.equal(coursePath.get("courseType"),userCourseDto.getCourseType()));
                    }
                    if(userCourseDto.getSubjectId() != null){
                        Join<Course, Subject> subjectPath = coursePath.join("subject");
                        predicates.add(criteriaBuilder.equal(subjectPath.get("id"),userCourseDto.getSubjectId()));
                    }
                }
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
    }
}
